import numpy as np
import string
from threading import Thread
import time
from time import sleep

def SummonKey(key):#生成两个子密钥
    keyP10=[None]*10
    #P10中的置换顺序可以更改
    P10=[3,5,2,7,4,10,1,9,8,6]
    for i in range(10):
        keyP10[i]=key[P10[i]-1]
    LS1=keyP10[0:5]
    LS2=keyP10[5:10]
    #第一轮向左滚动
    np.roll(LS1,-1)
    np.roll(LS1,-1)
    #P8置换生成k1,P8可更改
    key1=[None]*8
    P8=[6,3,7,4,8,5,10,9]
    combineKey1=LS1+LS2
    for i in range(8):
        key1[i]=combineKey1[P8[i]-1]
    #第二轮向左滚动
    np.roll(LS1,-1)
    np.roll(LS2,-1)
    #P8置换生成k2，P8可更改
    combineKey2=LS1+LS2
    key2=[None]*8
    for i in range(8):
        key2[i]=combineKey2[P8[i]-1]
    return key1,key2

def IP(P,s): # 1为初始置换，-1为最终置换
    #P8可更改
    match s:
        case 1:
            P8=[2,6,3,1,4,8,5,7]
        case -1:
            P8=[4,1,3,5,7,2,8,6]
    PIP=[None]*8
    for i in range(8):
        PIP[i]=P[P8[i]-1]
    return PIP

def F(R,key):#轮函数
    #EPBox,内容可更改
    EPBox=[4,1,2,3,2,3,4,1]
    REP=[None]*8
    for i in range(8):
        REP[i]=R[EPBox[i]-1]
    #与密钥进行异或运算
    REPXOR=[a^b for a,b in zip(REP,key)]
    #拆分
    L1=REPXOR[0:4]
    R1=REPXOR[4:8]
    #SBox
    SBox1=[[1,0,3,2],[3,2,1,0],[0,2,1,3],[3,1,0,2]]
    SBox2=[[0,1,2,3],[2,3,1,0],[3,0,1,2],[2,1,0,3]]
    L1temp=f"{SBox1[(L1[0]<<1)|L1[3]][(L1[2]<<1)|L1[3]]:02b}"#转为2位的二进制数
    R1temp=f"{SBox2[(R1[0]<<1)|R1[3]][(R1[2]<<1)|R1[3]]:02b}"
    #转为列表
    L1SB=[int(a) for a in L1temp]
    R1SB=[int(a) for a in R1temp]
    LR=L1SB+R1SB
    #P4替换
    RF=[None]*4
    P4=[2,4,3,1]
    for i in range(4):
        RF[i]=LR[P4[i]-1]
    return RF

def FK(P,key):#S-DES函数fk
    L=P[0:4]
    R=P[4:8]
    RF=F(R,key)
    #按位异或
    LFK=[a^b for a,b in zip(L,RF)]
    return LFK+R

def SW(P):#互换
    L=P[0:4]
    R=P[4:8]
    return R+L

def SDES(P,key,s):#S-DES,s为1为加密，s为2为解密
    #转为列表
    try:
        P1=[int(bit) for bit in str(P)]
    except ValueError as e:
        P1=ord(P)
        P1=format(P1, '08b')
        P1=[int(bit) for bit in str(P1)]
    key=[int(bit) for bit in str(key)]
    PIP=IP(P1,1)
    #若加密则k1在前，若解密则k2在前
    match s:
        case 1:
            key1,key2=SummonKey(key)
        case 2:
            key2,key1=SummonKey(key)
    PFK1=FK(PIP,key1)
    PSW=SW(PFK1)
    PFK2=FK(PSW,key2)
    PIPR=IP(PFK2,-1)
    #转为二进制数
    Pbin=''.join(map(str,PIPR))
    return Pbin


def Crack(plain_text,cipher_text,starting_key,ending_key):
    time1 = time.perf_counter()
    start_num=int(starting_key, 2)
    end_num=int(ending_key,2)
    getKey=[]
    flag = 0
    for i in range(start_num,end_num):
        key = bin(i)[2:]
        key = str(key)
        key = key.zfill(10)  # 填充到10位  
        result=SDES(plain_text,key,1)
        if(result == cipher_text):
            flag = i
            getKey.append(key)
    time2 = time.perf_counter()
    t=time2-time1
    if(flag == 0):
        return -1,-1
    else:
        return getKey,t

def Hyper_Thread_Crack(plain_text,cipher_text):
    current_time = time.strftime('%H:%M:%S', time.localtime())
    print(current_time)
    thread1 = Thread(target=Crack, args=("thread_1", plain_text, 'cipher_text', '0000000001', '0010000000'))  # 线程1：执行任务打印4个a
    thread2 = Thread(target=Crack, args=("thread_2", plain_text, cipher_text, '0010000001', '0100000000'))  # 线程1：执行任务打印4个a
    thread3 = Thread(target=Crack, args=("thread_3", plain_text, cipher_text, '0100000001', '0110000000'))  # 线程1：执行任务打印4个a
    thread4 = Thread(target=Crack, args=("thread_4", plain_text, cipher_text, '0110000001', '1000000000'))  # 线程1：执行任务打印4个a
    thread5 = Thread(target=Crack, args=("thread_5", plain_text, cipher_text, '1000000001', '1010000000'))  # 线程1：执行任务打印4个a
    thread6 = Thread(target=Crack, args=("thread_6", plain_text, cipher_text, '1010000001', '1100000000'))  # 线程1：执行任务打印4个a
    thread7 = Thread(target=Crack, args=("thread_7", plain_text, cipher_text, '1100000001', '1110000000'))  # 线程1：执行任务打印4个a
    thread8 = Thread(target=Crack, args=("thread_8", plain_text, cipher_text, '1110000001', '1111111111'))  # 线程1：执行任务打印4个a



    thread1.start()  # 线程1开始
    thread2.start()  # 线程2开始
    thread3.start()
    thread4.start()
    thread5.start()
    thread6.start()
    thread7.start()
    thread8.start()

    thread1.join()  # 等待线程1结束
    thread2.join()  # 等待线程2结束
    thread3.join()
    thread4.join()
    thread5.join()
    thread6.join()
    thread7.join()
    thread8.join()
    current_time = time.strftime('%H:%M:%S', time.localtime())
    print(current_time)

#测试
# RES=SDES(10110100,1110100101,1)
# print(RES)
# Crack('test','10110100','11011111','0000000011','1110100111')